#pragma Once
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include "log.hpp"
#include <pthread.h>

using namespace std;

// enum
// {
//     SOCKET_ERR = 1,
// };

// Log lg;
// int main(int argc, char *argv[])
// {
//     if (argc != 3)
//     {
//         cout << "usage: " << argv[0] << " serverip serverport" << endl;
//         exit(0);
//     }
//     // 这里只是 初始化 服务器的 sockaddr_in .
//     string serverip = argv[1];
//     uint16_t serverport = stoi(argv[2]);

//     struct sockaddr_in server;
//     bzero(&server, sizeof(server));
//     server.sin_family = AF_INET;
//     server.sin_port = htons(serverport);
//     server.sin_addr.s_addr = inet_addr(serverip.c_str());

//     // 创建网络文件描述符
//     int socketfd = socket(AF_INET, SOCK_DGRAM, 0);
//     if (socketfd < 0)
//     {
//         lg(Fatal, "create socket fail,socket : %d ", socketfd);
//         exit(SOCKET_ERR);
//     }
//     lg(Info, "socket create success, sockfd: %d", socketfd);

//     // 客户端不需要自己bind fd ，由操作系统完成

//     char inbuff[1024];
//     string message;
//     while (true)
//     {
//         cout << "Please enter# ";
//         getline(cin, message);

//         socklen_t len = sizeof(server);
//         ssize_t n = sendto(socketfd, message.c_str(), message.size(), 0, (struct sockaddr *)&server, len);
//         if (n < 0)
//         {
//             cout << "sendto fail" << endl;
//             exit(1);
//         }

//         struct sockaddr_in recev;
//         socklen_t len1 = sizeof(recev);
//         ssize_t s = recvfrom(socketfd, inbuff, sizeof(inbuff) - 1, 0, (struct sockaddr *)&recev, &len1);
//         if (s > 0)
//         {
//             inbuff[s] = 0;
//             cerr << inbuff << endl;
//         }
//     }

//     close(socketfd);
//     return 0;
// }

struct ThreadData
{
    struct sockaddr_in server;
    int socketfd;
};

enum
{
    SOCKET_ERR = 1,
};

void *recv_message(void *argc)
{
    struct ThreadData *td = static_cast<struct ThreadData *>(argc);
    char inbuff[1024];
    while (true)
    {
        memset(inbuff, 0, sizeof(inbuff)); //需要初始化，因为recvfrom是覆盖outbuff进行写入
        struct sockaddr_in recev;
        socklen_t len = sizeof(recev);

        ssize_t s = recvfrom(td->socketfd, inbuff, 1023, 0, (struct sockaddr *)&recev, &len);
        if (s > 0)
        {
            inbuff[s] = 0;
            cerr << inbuff << endl; // cerr
        }
    }
}

void *send_message(void *argc)
{
    struct ThreadData *td = static_cast<struct ThreadData *>(argc);
    string message;
    while (true)
    {
        cout << "Please enter# ";
        getline(cin, message);

        socklen_t len = sizeof(td->server);
        ssize_t n = sendto(td->socketfd, message.c_str(), message.size(), 0, (struct sockaddr *)&td->server, len);
        if (n < 0)
        {
            cout << "sendto fail" << endl;
            exit(1);
        }
    }
}

Log lg;
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        cout << "usage: " << argv[0] << " serverip serverport" << endl;
        exit(0);
    }

    struct ThreadData td;
    memset(&td, 0, sizeof(td));
    // 这里只是 初始化 服务器的 sockaddr_in .
    string serverip = argv[1];
    uint16_t serverport = stoi(argv[2]);

    td.server.sin_family = AF_INET;
    td.server.sin_port = htons(serverport);
    td.server.sin_addr.s_addr = inet_addr(serverip.c_str());

    // 创建网络文件描述符
    td.socketfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (td.socketfd < 0)
    {
        lg(Fatal, "create socket fail,socket : %d ", td.socketfd);
        exit(SOCKET_ERR);
    }
    lg(Info, "socket create success, sockfd: %d", td.socketfd);

    // 客户端不需要自己bind fd ，由操作系统完成

    pthread_t recvr, sender;
    pthread_create(&recvr, nullptr, recv_message, &td);
    pthread_create(&sender, nullptr, send_message, &td);

    pthread_join(recvr, nullptr);
    pthread_join(sender, nullptr);

    close(td.socketfd);
    return 0;
}
